package com.springboot.demo.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.springboot.demo.entity.*;
import com.springboot.demo.exception.BusinessException;
import com.springboot.demo.mapper.*;
import com.springboot.demo.service.InboxService;
import com.springboot.demo.service.UserService;
import com.springboot.demo.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @author wubc683
 * @desc
 * @date 2021-07-26 10:05
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    SmsCodeUtils smsCodeUtils;
    @Autowired
    PasswordEncodeUtils passwordEncodeUtils;
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    ImgCodeUtils imgCodeUtils;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    MenuMapper menuMapper;
    @Autowired
    PageUtils pageUtils;
    @Autowired
    InboxService inboxService;
    @Autowired
    InboxMapper inboxMapper;
    @Autowired
    MapMapper mapMapper;
    @Autowired
    DeviceMapper deviceMapper;
    @Autowired
    SceneMapper sceneMapper;
    @Autowired
    SimpMessagingTemplate simpMessagingTemplate;

    /**
     * 实现security框架默认方法
     * 通过用户名获取用户
     *
     * @param username
     * @return: com.springboot.demo.entity.User
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.getUserByUsername(username);
        if (null == user) {
            throw new BusinessException(ResponseResult.USERNAME_NOT_EXISTED);
        }
        User userInfoById = getUserInfoById(user.getId());
        userInfoById.setLastLoginTime(new Date());
        userMapper.updateUserLoginTime(userInfoById);
        if (userInfoById.getParentId() == 0) {
            redisUtils.delete(Constant.CACHE_PREFIX.USER + userInfoById.getId());
        } else {
            redisUtils.delete(Constant.CACHE_PREFIX.USER + userInfoById.getId());
            redisUtils.delete(Constant.CACHE_PREFIX.RELATIVEUSER + userInfoById.getId());
        }
        return new UserDetailsImpl(userInfoById);
    }

    /**
     * 检查用户名是否存在
     *
     * @param username
     * @return: com.springboot.demo.utils.ResponseUtils<java.lang.String>
     */
    @Override
    public Boolean IsUsernameExisted(String username) {
        User user = userMapper.getUserByUsername(username);
        if (null == user) {
            return false;
        }
        return true;
    }

    /**
     * 注册用户
     *
     * @param user
     * @return: com.springboot.demo.utils.ResponseResult
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveUser(User user) {
        // 校验短信验证码
        smsCodeUtils.check(user.getPhone(), user.getSmsCode());
        // 校验用户名是否存在
        Boolean b = IsUsernameExisted(user.getUsername());
        if (b) {
            throw new BusinessException(ResponseResult.USERNAME_EXISTED);
        }
        // 校验手机号是否存在
        Boolean b1 = isPhoneRegistered(user.getPhone());
        if (b1) {
            throw new BusinessException(ResponseResult.PHONE_IS_REGISTERED);
        }
        // 检查两次密码是否一样
        if (!user.getPassword().equals(user.getRetryPassword())) {
            throw new BusinessException(ResponseResult.PASSWORD_RETRY_NOT_EQUAL);
        }
        // 密码加密
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(user.getPassword());
        user.setPassword(encode);
        // 注册进来的都是管理员，父id都为0
        user.setParentId(0L);
        user.setRid(Constant.ADMIN);
        user.setCreateDate(new Date());
        user.setExpireDate(new Date());
        user.setIsEnabled(false);
        user.setIsLocked(false);
        user.setIsPhoneChecked(true);
        user.setRecordCount(Constant.HISTORY_RECORD_LIMIT_COUNT);
        user.setDeleteFlag("");

        // 插入数据库
        userMapper.saveUser(user);
        // 设置默认权限
        userMapper.insertUserRoleByUidAndRid(user.getId(), Constant.ADMIN);
        userMapper.insertUserRoleByUidAndRid(user.getId(), Constant.USER);
        String content = "用户：" + user.getUsername() + "注册了账号！";
        Inbox inbox = new Inbox(user.getId(), Constant.MsgType.SYSTEM, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(user.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
        // 让短信验证码失效
        smsCodeUtils.del(user.getPhone());
    }

    @Override
    public void updatePasswordByPhone(User user) {
        // 校验两次输入密码是否一致
        if (!user.getPassword().equals(user.getRetryPassword())) {
            throw new BusinessException(ResponseResult.PASSWORD_RETRY_NOT_EQUAL);
        }
        // 校验手机号是否已注册
        Boolean phoneRegistered = isPhoneRegistered(user.getPhone());
        if (!phoneRegistered) {
            throw new BusinessException(ResponseResult.PHONE_NOT_REGISTERED);
        }
        // 校验短信验证码
        smsCodeUtils.check(user.getPhone(), user.getSmsCode());
        // 加密密码，存入数据库
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(user.getPassword());
        userMapper.updatePasswordByPhone(user.getPhone(), encode);
        // 让短信验证码失效
        smsCodeUtils.del(user.getPhone());
    }

    /**
     * 查询手机号是否已注册
     *
     * @param phone
     * @return: com.springboot.demo.utils.ResponseResult
     */
    @Override
    public Boolean isPhoneRegistered(String phone) {
        if (!CommonUtils.checkPhone(phone)) {
            throw new BusinessException(ResponseResult.PHONE_FORMAT_ERROR);
        }
        User user = userMapper.getUserByPhone(phone);
        if (null == user) {
            return false;
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = "user", key = "#id"),
            @CacheEvict(value = "relativeUser", key = "#id")
    })
    public void updatePassword(Long id, User user) {
        User implUser = getUserInfoById(id);
        // 检查两次新密码是否一样
        if (!user.getPassword().equals(user.getRetryPassword())) {
            throw new BusinessException(ResponseResult.PASSWORD_RETRY_NOT_EQUAL);
        }
        // 校验旧密码是否正确
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        if (!bCryptPasswordEncoder.matches(user.getOldPassword(), implUser.getPassword())) {
            throw new BusinessException(ResponseResult.PASSWORD_ERROR);
        }
        String encode = bCryptPasswordEncoder.encode(user.getPassword());
        userMapper.updatePasswordById(implUser.getId(), encode);
    }

    @Override
    public String findUsernameByPhone(User user) {
        // 校验短信验证码
        smsCodeUtils.check(user.getPhone(), user.getSmsCode());
        User userInfo = userMapper.getUserByPhone(user.getPhone());
        if (null == userInfo) {
            throw new BusinessException(ResponseResult.PHONE_NOT_REGISTERED);
        }
        // 让短信验证码失效
        smsCodeUtils.del(user.getPhone());
        return userInfo.getUsername();
    }

    /**
     * 获取用户信息
     *
     * @param id
     * @return: com.springboot.demo.entity.User
     */
    @Override
    @Cacheable(value = "user", key = "#id")
    public User getUserInfoById(Long id) {
        User userById = userMapper.getUserById(id);
        if (userById == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        return userById;
    }

    @Override
    public PageResult getRelativeAccounts(User user, PageRequest pageRequest) {
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<User> userList = userMapper.getUserByParentId(user.getId());
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(userList));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertRelativeAccount(Long id, User user) {
        User parentUser = getUserInfoById(id);
        // 校验用户名是否存在
        Boolean b1 = IsUsernameExisted(user.getUsername());
        if (b1) {
            throw new BusinessException(ResponseResult.USERNAME_EXISTED);
        }
        // 检查两次新密码是否一样
        if (!user.getPassword().equals(user.getRetryPassword())) {
            throw new BusinessException(ResponseResult.PASSWORD_RETRY_NOT_EQUAL);
        }
        if (!"".equals(user.getPhone()) && !CommonUtils.checkPhone(user.getPhone())) {
            throw new BusinessException(ResponseResult.PHONE_FORMAT_ERROR);
        }
        // 检查用户是否拥有此权限
        List<Long> roleIdByUserId = userMapper.getRoleIdByUserId(parentUser.getId());
        if (roleIdByUserId == null || roleIdByUserId.isEmpty() || !roleIdByUserId.contains(user.getRid())) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_ROLE);
        }
        // 不能分配管理员权限
        if (Constant.ADMIN.equals(user.getRid())) {
            throw new BusinessException(ResponseResult.ROLE_ADMIN_CAN_NOT_ALLOT);
        }
        // 密码加密
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(user.getPassword());
        user.setPassword(encode);
        // 设置关联账号的父账号
        user.setParentId(parentUser.getId());
        user.setCreateDate(parentUser.getCreateDate());
        user.setExpireDate(parentUser.getExpireDate());
        user.setIsEnabled(true);
        user.setIsLocked(false);
        user.setIsPhoneChecked(false);
        user.setRecordCount(Constant.HISTORY_RECORD_LIMIT_COUNT);
        user.setDeleteFlag("");

        // 保存关联用户信息
        userMapper.saveRelativeUser(user);
        userMapper.insertUserRoleByUidAndRid(user.getId(), user.getRid());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = "relativeUser", key = "#user.id"),
            @CacheEvict(value = "user", key = "#user.id")
//            @CacheEvict(value = "user", key = "#id", condition = "#id != null")
    })
    public void updateRelativeAccount(Long pid, User user) {
        // 检查用户是否存在
        User queryUser = getUserInfoById(user.getId());
        if (queryUser == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        // 校验是否是关联账号
        if (!pid.equals(queryUser.getParentId())) {
            throw new BusinessException(ResponseResult.USER_NOT_RELATIVE);
        }
        // 校验用户名是否重复
        User userByUsername = userMapper.getUserByUsername(user.getUsername());
        if (userByUsername != null && !userByUsername.getId().equals(user.getId())) {
            throw new BusinessException(ResponseResult.USERNAME_EXISTED);
        }
        // 校验电话,如果前端传来的电话格式是空格，则忽略
        if ("".equals(user.getPhone())) {
            user.setIsPhoneChecked(false);
        } else {
            if (!CommonUtils.checkPhone(user.getPhone())) {
                throw new BusinessException(ResponseResult.PHONE_FORMAT_ERROR);
            }
            if (!user.getPhone().equals(queryUser.getPhone())) {
                user.setIsPhoneChecked(false);
            }
        }
        // 检查用户是否拥有此权限
        List<Long> roleIdByUserId = userMapper.getRoleIdByUserId(pid);
        if (roleIdByUserId == null || roleIdByUserId.isEmpty() || !roleIdByUserId.contains(user.getRid())) {
            throw new BusinessException(ResponseResult.USER_DO_NOT_HAVE_THIS_ROLE);
        }
        // 不能分配管理员权限
        if (Constant.ADMIN.equals(user.getRid())) {
            throw new BusinessException(ResponseResult.ADMIN_CAN_NOT_ALLOT);
        }
        // 检查两次新密码是否一样
        if (StringUtils.hasLength(user.getPassword())) {
            if (!user.getPassword().equals(user.getRetryPassword())) {
                throw new BusinessException(ResponseResult.PASSWORD_RETRY_NOT_EQUAL);
            }
            String passwordPattern = "^[a-zA-Z0-9~!@#$%^&*()_+`\\-=,.<>;':\"/\\\\?|{}\\[\\]]{5,31}$";
            Pattern pattern = Pattern.compile(passwordPattern);
            Matcher match = pattern.matcher(user.getPassword());
            if (!match.matches()) {
                throw new BusinessException(ResponseResult.PASSWORD_FORMAT_ERROR);
            }
            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            String encode = bCryptPasswordEncoder.encode(user.getPassword());
            user.setPassword(encode);
            user.setIsPhoneChecked(false);
        } else {
            user.setPassword(queryUser.getPassword());
            user.setIsPhoneChecked(queryUser.getIsPhoneChecked());
        }
        // 密码加密
        user.setPhone(user.getPhone());
        // 更新关联用户信息
        userMapper.updateRelativeUser(user);
        userMapper.updateUserRoleById(user.getId(), user.getRid());
    }

    /**
     * 删除关联用户
     *
     * @param pid
     * @param id
     * @return: void
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = "user", key = "#id"),
            @CacheEvict(value = "relativeUser", key = "#pid")
    })
    public void deleteRelativeAccount(Long pid, Long id) {
        // 校验关联用户是否为空
        User relativeUser = getUserInfoById(id);
        if (relativeUser == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        // 校验是否是关联账号
        if (!pid.equals(relativeUser.getParentId())) {
            throw new BusinessException(ResponseResult.USER_NOT_RELATIVE);
        }
        // 删除关联用户账号
        userMapper.deleteUserByUserId(id, UUID.randomUUID().toString());
    }

    /**
     * 更新用户信息
     *
     * @param id
     * @param user
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = "user", key = "#id"),
    })
    public void updateUserInfo(Long id, User user) {
        User implUser = getUserInfoById(id);
        // 校验用户名是否重复
        User userByUsername = userMapper.getUserByUsername(user.getUsername());
        if (userByUsername != null && !userByUsername.getId().equals(implUser.getId())) {
            throw new BusinessException(ResponseResult.USERNAME_EXISTED);
        }
        // 管理员变更手机号需要验证
        if (implUser.getParentId().equals(0L)) {
            if (!CommonUtils.checkPhone(user.getPhone())) {
                throw new BusinessException(ResponseResult.PHONE_FORMAT_ERROR);
            }
            if (!implUser.getPhone().equals(user.getPhone())) {
                throw new BusinessException(ResponseResult.ADMIN_CHANGE_PHONE_NEED_VERIFY);
            }
        } else {
            if (!"".equals(user.getPhone()) && !CommonUtils.checkPhone(user.getPhone())) {
                throw new BusinessException(ResponseResult.PHONE_FORMAT_ERROR);
            }
        }
        userMapper.updateUserByNameAndPhone(implUser.getId(), user.getUsername(), user.getPhone());
    }

    @Override
    @Cacheable(value = "relativeUser", key = "#userId")
    public User getRelativeAccount(User implUser, Long userId) {
        // 检查账号是否存在
        User userById = userMapper.getUserById(userId);
        if (null == userById) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        // 检查是否是关联账号
        if (!implUser.getId().equals(userById.getParentId())) {
            throw new BusinessException(ResponseResult.USER_NOT_RELATIVE);
        }
        return userById;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSystemLog(Long uid, SystemLog systemLog) {
        userMapper.insertSystemLog(systemLog);
        userMapper.insertUserSystemLog(uid, systemLog.getId());
    }

    @Override
    public PageResult getSystemLog(User user, PageRequest pageRequest) {
        // 获取管理员及其关联用户的所有登录日志
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<SystemLog> systemLogByUid = userMapper.getSystemLogByUid(user.getId());
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(systemLogByUid));
    }

    @Override
    public void checkUsername(String username) {
        User user = userMapper.getUserByUsername(username);
        if (null != user) {
            throw new BusinessException(ResponseResult.USERNAME_EXISTED);
        }
    }

    @Override
    public void getProfile(Long id, Long userId, HttpServletResponse response) throws IOException {
        User implUser = getUserInfoById(id);
        // 只能获取关联账号的头像
        User userInfoById = getUserInfoById(userId);
        if (userInfoById == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        if (!(implUser.getId().equals(userInfoById.getParentId()) || implUser.getParentId().equals(userId)
                || implUser.getParentId().equals(userInfoById.getParentId()))) {
            throw new BusinessException(ResponseResult.FORBIDDEN);
        }
//        String path = Constant.PROFILE_PATH + "\\" + userId + "\\profile"+userId+".png";
        String path = Constant.PROFILE_PATH + "/" + userId + "/profile" + userId + ".png";
        File file = new File(path);
        String imageData = null;
        // 头像不存在就用默认头像
        if (!file.exists()) {
//            path = Constant.PROFILE_PATH + "\\default\\profile.png";
            path = Constant.PROFILE_PATH + "/default/profile.png";
            file = new File(path);
            if (!file.exists()) {
                throw new BusinessException(ResponseResult.PROFILE_NOT_FOUNT);
            }
        }
        FileInputStream fis = new FileInputStream(file);
        byte[] data = new byte[fis.available()];
        fis.read(data);
        fis.close();
        response.setContentType("image/png");
        OutputStream out = response.getOutputStream();
        out.write(data);
        out.flush();
        out.close();
    }

    @Override
    public void checkImgCode(HttpServletRequest request, String imgCode) {
        Object obj = request.getSession().getAttribute(Constant.SESSION_IMGCODE);
        if (obj == null || !imgCode.equals(obj.toString())) {
            throw new BusinessException(ResponseResult.IMGCODE_ERROR);
        }
    }

    @Override
    @Caching(evict = {
            @CacheEvict(value = "user", key = "#id"),
            @CacheEvict(value = "relativeUser", key = "#id")
    })
    public void updatePhone(Long id, User user) {
        User userInfoById = getUserInfoById(id);
        smsCodeUtils.check(user.getPhone(), user.getSmsCode());
        userMapper.updateUserPhoneAndState(id, user.getPhone(), true);
        // 让短信验证码失效
        smsCodeUtils.del(user.getPhone());
    }

    @Override
    public List<String> getUserByName(User implUser, String username, Long deviceClusterId) {
        // 限制搜索范围为管理员以及其关联用户
        Long adminId = null;
        if (implUser.getParentId().equals(0L)) {
            adminId = implUser.getId();
        } else {
            adminId = implUser.getParentId();
        }
        // 检查用户是否有此设备群
        if (deviceClusterId != null) {
            Integer res = deviceMapper.isUserInDeviceCluster(implUser.getId(), deviceClusterId);
            if (res == 0) {
                throw new BusinessException(ResponseResult.USER_NOT_IN_DEVICE_CLUSTER);
            }
        }
        return userMapper.searchUserByName(adminId, implUser.getId(), username, deviceClusterId);
    }

    @Override
    public PageResult getAllAdminUser(PageRequest pageRequest) {
        PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
        List<User> allAdminUser = userMapper.getAllAdminUser();
        return pageUtils.getPageResult(pageRequest, new PageInfo<>(allAdminUser));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void activeUser(Long userId, Long regId) {
        User userInfoById = getUserInfoById(regId);
        if (userInfoById == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        if (userInfoById.getParentId() != 0) {
            throw new BusinessException(ResponseResult.USER_NOT_ADMIN);
        }
        if (userInfoById.getIsEnabled().equals(true)) {
            throw new BusinessException(ResponseResult.USER_IS_ENABLED);
        }
        // 激活用户并且设置过期时间,默认1个月有效期
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.MONTH, Constant.REGISTER_VALID_MONTH);
        Date time = calendar.getTime();
        userMapper.updateUserIsEnabledAndExpireDate(regId, true, time);
        String content = "您激活了用户：" + userInfoById.getUsername();
        User owner = userMapper.getUserById(userId);
        Inbox inbox = new Inbox(owner.getId(), Constant.MsgType.SYSTEM, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(owner.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = "user", key = "#lockUserId"),
            @CacheEvict(value = "relativeUser", key = "#lockUserId")
    })
    public void lockUser(Long ownerId, Long lockUserId, Integer locked) {
        User userInfoById = getUserInfoById(lockUserId);
        if (userInfoById == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        User ownerUser = getUserInfoById(ownerId);
        // 只能是超级管理员锁定/解锁管理员，和管理员锁定/解锁关联用户
        if ((ownerUser.getRid().equals(Constant.SUPER_ADMIN) && !userInfoById.getRid().equals(Constant.ADMIN)) ||
                (ownerUser.getRid().equals(Constant.ADMIN) && !userInfoById.getParentId().equals(ownerUser.getId()))) {
            throw new BusinessException(ResponseResult.LOCK_USER_ILLEGAL);
        }
        if (locked != 0 && locked != 1) {
            throw new BusinessException(ResponseResult.PARAM_VALUE_ILLEGAL);
        }

        String content;
        if (locked == 0) {
            if (userInfoById.getIsLocked().equals(false)) {
                throw new BusinessException(ResponseResult.USER_UNLOCK);
            }
            content = "您解锁了用户：" + userInfoById.getUsername();
        } else {
            if (userInfoById.getIsLocked().equals(true)) {
                throw new BusinessException(ResponseResult.USER_LOCK);
            }
            content = "您锁定了用户：" + userInfoById.getUsername();
        }
        userMapper.updateUserIsLocked(lockUserId, locked);
        User owner = userMapper.getUserById(ownerId);
        Inbox inbox = new Inbox(ownerId, Constant.MsgType.EVENT, Constant.WEBSOCKETCMD.COMMON_MESSAGE, content);
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(owner.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = "user", key = "#regId"),
            @CacheEvict(value = "relativeUser", key = "#regId")
    })
    public void addUserExpireDate(Long ownerId, Long regId, Integer month) {
        User userInfoById = getUserInfoById(regId);
        if (userInfoById == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        // 被操作对象需要是管理员
        if (!userInfoById.getParentId().equals(0L)) {
            throw new BusinessException(ResponseResult.ROLE_NOT_ADMIN);
        }
        Calendar cal = Calendar.getInstance();
        // 账号已经过期,则续期的开始时间为当前时间,没有过期，则开始时间为过期时间
        if (userInfoById.getExpireDate().compareTo(new Date()) < 0) {
            cal.setTime(new Date());
        } else {
            cal.setTime(userInfoById.getExpireDate());
        }
        cal.add(Calendar.MONTH, month);
        Date expireTime = cal.getTime();
        // 更新管理员账号及其关联账号到期时间
        userMapper.updateUserExpireDate(regId, expireTime);
        // 清除关联用户的缓存信息
        List<Long> relativeUserIds = userMapper.getRelativeUserIdByAdminId(regId);
        for (int i = 0; i < relativeUserIds.size(); i++) {
            redisUtils.delete("relativeUser::" + relativeUserIds.get(i));
            redisUtils.delete("user::" + relativeUserIds.get(i));
        }
        User owner = userMapper.getUserById(ownerId);
        String regContent = "您的账号续费" + month + "个月成功,账号到期时间为：" + expireTime;
        Inbox inbox = new Inbox(regId, Constant.MsgType.SYSTEM, Constant.WEBSOCKETCMD.COMMON_MESSAGE, regContent);
        inboxMapper.saveInbox(inbox);
        simpMessagingTemplate.convertAndSendToUser(userInfoById.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox);

        String ownerContent = "您为账号：" + userInfoById.getUsername() + "续费了" + month + "个月,该账号到期时间为：" + expireTime;
        Inbox inbox1 = new Inbox(ownerId, Constant.MsgType.SYSTEM, Constant.WEBSOCKETCMD.COMMON_MESSAGE, ownerContent);
        inboxMapper.saveInbox(inbox1);
        simpMessagingTemplate.convertAndSendToUser(owner.getUsername(), Constant.WEBSOCKET_PRIVATE_ROOTINGKEY, inbox1);
    }

    @Override
    public void checkUserRelative(User user1, User user2) {
        if (user1 == null || user2 == null) {
            throw new BusinessException(ResponseResult.USER_NOT_EXISTED);
        }
        boolean b1 =
                user1.getParentId().equals(0L) && !user2.getParentId().equals(0L) && !user1.getId().equals(user2.getParentId());
        boolean b2 =
                user2.getParentId().equals(0L) && !user1.getParentId().equals(0L) && !user2.getId().equals(user1.getParentId());
        boolean b3 = user1.getParentId().equals(0L) && user2.getParentId().equals(0L);
        boolean b4 =
                !user1.getParentId().equals(0L) && !user2.getParentId().equals(0L) && !user1.getParentId().equals(user2.getParentId());
        if (b1 || b2 || b3 || b4) {
            throw new BusinessException(ResponseResult.USER_NOT_RELATIVE);
        }
    }
}
